use syn::{File, Item, ItemImpl, Type};
use quote::quote;
use quote::ToTokens;
use tempfile::NamedTempFile;
use std::process::Command;
use std::env;
use std::fs;
use std::io::Write;

fn main() {
    // 获取传递的文件名
    let args: Vec<String> = env::args().collect();
    if args.len() < 2 {
        eprintln!("Usage: merge-impl/target/debug/merge-impl -- <filename>");
        return;
    }
    let filename = &args[1];

    // 读取文件内容
    let input_code = fs::read_to_string(filename).expect("Unable to read file");

    // 解析 Rust 代码
    let ast: File = syn::parse_str(&input_code).expect("Unable to parse Rust code");
    
    // 提取所有的impl块
    let mut impl_blocks = Vec::new();
    let mut other_items = Vec::new();
    for item in ast.items {
        //if let syn::Item::Impl(impl_block) = item {
        //    impl_blocks.push(impl_block);
        //}
        match item {
            Item::Impl(impl_block) => impl_blocks.push(impl_block),
            _ => other_items.push(item),
        }
    }

    // 合并impl块
    let mut merged_impls = std::collections::HashMap::new();
    for impl_block in impl_blocks {
        //let struct_name = impl_block.self_ty.to_token_stream().to_string();
        
        let struct_name = match &*impl_block.self_ty {
            Type::Path(path) => path.path.segments.last().unwrap().ident.clone(),
            _ => panic!("Unsupported type"),
        };

        let methods = impl_block.items;

        merged_impls
            .entry(struct_name)
            .or_insert_with(Vec::new)
            .extend(methods);
    }

    // 生成合并后的Rust源文件
    let mut output_content = String::new();

    // 添加其他Item
    for item in other_items {
        output_content.push_str(&item.to_token_stream().to_string());
        output_content.push('\n');
    }

    for (struct_name, methods) in merged_impls {
        let impl_block = quote! {
            impl #struct_name {
                #(#methods)*
            }
        };
        output_content.push_str(&impl_block.to_string());
        output_content.push('\n');
    }
    
    // 将过滤后的代码写入临时文件
    let mut temp_file = NamedTempFile::new().expect("Failed to create temp file!");
    writeln!(temp_file, "{}", output_content).expect("Failed to write code into temp file!");

    // 使用 rustfmt 格式化代码
    let temp_path = temp_file.path().to_str().unwrap();
    Command::new("rustfmt")
        .arg(temp_path)
        .status()
        .expect("Failed to call rustfmt");

    // 格式化生成的代码
    let formatted_code = fs::read_to_string(temp_path).expect("Failed to read back formatted file!");
    
    // 输出结果
    println!("{}", formatted_code);
}
